//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.1.1
#include "fsmc8080_bsp.h"


static WHT_FSMC8080_Info_t WHT_LCD8080_Info = { 0 };

/*FSMC8080 GPIO初始化*/
static void WHT_FSMC8080_BSP_GPIO_Init(void)
{
    //FSMC数据
    WHT_GPIO_BSP.WHT_Set_Clock(PortD, ENABLE);
    WHT_GPIO_BSP.WHT_Set_Clock(PortE, ENABLE);
    WHT_GPIO_BSP.WHT_Set_State(PortD, FSMC_D0_PIN | FSMC_D1_PIN | FSMC_D2_PIN | FSMC_D3_PIN, Hig);
    WHT_GPIO_BSP.WHT_Set_State(PortE, FSMC_D4_PIN | FSMC_D5_PIN | FSMC_D6_PIN | FSMC_D7_PIN, Hig);
    WHT_GPIO_BSP.WHT_Set_Mode(PortD, FSMC_D0_PIN | FSMC_D1_PIN | FSMC_D2_PIN | FSMC_D3_PIN, Mode_AF_PP);
    WHT_GPIO_BSP.WHT_Set_Mode(PortE, FSMC_D4_PIN | FSMC_D5_PIN | FSMC_D6_PIN | FSMC_D7_PIN, Mode_AF_PP);
#if (FSMC8080_Data_Width_bit == 16)
    WHT_GPIO_BSP.WHT_Set_State(PortD, FSMC_D13_PIN | FSMC_D14_PIN | FSMC_D15_PIN, Hig);
    WHT_GPIO_BSP.WHT_Set_State(PortE, FSMC_D8_PIN | FSMC_D9_PIN | FSMC_D10_PIN | FSMC_D11_PIN | FSMC_D12_PIN, Hig);
    WHT_GPIO_BSP.WHT_Set_Mode(PortD, FSMC_D13_PIN | FSMC_D14_PIN | FSMC_D15_PIN, Mode_AF_PP);
    WHT_GPIO_BSP.WHT_Set_Mode(PortE, FSMC_D8_PIN | FSMC_D9_PIN | FSMC_D10_PIN | FSMC_D11_PIN | FSMC_D12_PIN, Mode_AF_PP);
#endif
    //FSMC片选
    WHT_GPIO_BSP.WHT_Set_Clock(LCD_CS_PORT, ENABLE);
    WHT_GPIO_BSP.WHT_Set_Mode(LCD_CS_PORT, LCD_CS_PIN, Mode_AF_PP);
    //FSMC地址
    WHT_GPIO_BSP.WHT_Set_Clock(LCD_DC_PORT, ENABLE);
    WHT_GPIO_BSP.WHT_Set_Mode(LCD_DC_PORT, LCD_DC_PIN, Mode_AF_PP);
    //写使能
    WHT_GPIO_BSP.WHT_Set_Clock(LCD_WR_PORT, ENABLE);
    WHT_GPIO_BSP.WHT_Set_Mode(LCD_WR_PORT, LCD_WR_PIN, Mode_AF_PP);
    //读使能
    WHT_GPIO_BSP.WHT_Set_Clock(LCD_RD_PORT, ENABLE);
    WHT_GPIO_BSP.WHT_Set_Mode(LCD_RD_PORT, LCD_RD_PIN, Mode_AF_PP);
}
/*FSMC8080配置*/
static void WHT_FSMC8080_BSP_Config(void)
{
	FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
	FSMC_NORSRAMTimingInitTypeDef  readWriteTiming;

	/*使能FSMC外设时钟*/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);

	//地址建立时间（ADDSET）为1个HCLK 2/72M=28ns
	readWriteTiming.FSMC_AddressSetupTime = 0x01;	
	//数据保持时间（DATAST）+ 1个HCLK = 5/72M=70ns
	readWriteTiming.FSMC_DataSetupTime = 0x04;		 
	//地址保持时间（ADDHLD）模式B未用到
	readWriteTiming.FSMC_AddressHoldTime = 0x00;	 
	//设置总线转换周期，仅用于复用模式的NOR操作
	readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
	//设置时钟分频，仅用于同步类型的存储器
	readWriteTiming.FSMC_CLKDivision = 0x00;	
	//数据保持时间，仅用于NOR
	readWriteTiming.FSMC_DataLatency = 0x00;		
	//模式B,异步NOR FLASH模式，与LCD的8080时序匹配
	readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_B;	 
    
	// 选择FSMC映射的存储区域： Bank1 NORSRAMx
	FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_BANK_NORSRAMx; 
	//设置地址总线与数据总线是否复用，仅用于NOR
	FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; 
	//设置要控制的存储器类型：NOR类型
	FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_NOR;   
	
	//存储器数据宽度：16位
#if (FSMC8080_Data_Width_bit == 16)
    FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
#else
    FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;
#endif
	
	//设置是否使用突发访问模式，仅用于同步类型的存储器
	FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;
	//设置是否使能等待信号，仅用于同步类型的存储器
	FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
	//设置等待信号的有效极性，仅用于同步类型的存储器
	FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
	//设置是否支持把非对齐的突发操作，仅用于同步类型的存储器
	FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; 
	//设置等待信号插入的时间，仅用于同步类型的存储器
	FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
	//存储器写使能 
	FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
	//不使用等待信号
	FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;  		
	// 不使用扩展模式，读写使用相同的时序
	FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; 
	//突发写操作
	FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;  
	//读写时序配置
	FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
	//读写同样时序，使用扩展模式时这个配置才有效
	FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming; 

	FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);  //初始化FSMC配置

	FSMC_NORSRAMCmd(FSMC_BANK_NORSRAMx, ENABLE);  // 使能BANK
}
/*FSMC8080初始化*/
static void WHT_FSMC8080_BSP_Init(void)
{
	WHT_FSMC8080_BSP_GPIO_Init();
	WHT_FSMC8080_BSP_Config();
}


/*FSMC8080互斥锁*/
static ErrorStatus WHT_FSMC8080_BSP_Set_Mutex(void)
{
	if (WHT_LCD8080_Info.BSP_Mutex == RESET)//互斥锁关闭
	{
		WHT_LCD8080_Info.BSP_Mutex = SET;   //互斥锁打开
		return SUCCESS;
	}
	else
		return ERROR;
}
/*FSMC8080解锁*/
static void WHT_FSMC8080_BSP_Clr_Mutex(void)
{
	WHT_LCD8080_Info.BSP_Mutex = RESET;
}



#if (FSMC8080_Data_Width_bit == 16)
	/*FSMC8080写命令*/
	static void WHT_FSMC8080_BSP_Write_Cmd(unsigned short cmd)
	{
		*(volatile unsigned short*)FSMC8080_Write_CMD = cmd;
	}
	/*FSMC8080写数据*/
	static void WHT_FSMC8080_BSP_Write_Data(const unsigned short* input_buf, unsigned int count)
	{
		while (count--)
		{
			*(volatile unsigned short*)FSMC8080_Write_DATA = *input_buf;
			input_buf++;
		}
	}
	/*FSMC8080写缓存*/
	static void WHT_FSMC8080_BSP_Write(unsigned short cmd, const unsigned short* input_buf, unsigned int count)
	{
		*(volatile unsigned short*)FSMC8080_Write_CMD = cmd;
		WHT_FSMC8080_BSP_Write_Data(input_buf, count);
	}
	/*FSMC8080读数据*/
	static void WHT_FSMC8080_BSP_Read(unsigned short cmd, uint16_t* output_buf, unsigned int count)
	{
		*(volatile unsigned short*)FSMC8080_Write_CMD = cmd;
		while (count--)
		{
			*output_buf = *(volatile unsigned short*)FSMC8080_Read_DATA;
			output_buf++;
		}
	}
#else
#endif // (FSMC8080_Data_Width_bit == 16)

/*FSMC8080注册API*/
void WHT_FSMC8080_BSP_Register(WHT_FSMC8080_BSP_t* bsp)
{
	if (WHT_LCD8080_Info.Mount_Count == 0)
		WHT_FSMC8080_BSP_Init();
	WHT_LCD8080_Info.Mount_Count++;
    
	bsp->WHT_Info          = &WHT_LCD8080_Info;
	bsp->WHT_Set_BSP_Mutex = WHT_FSMC8080_BSP_Set_Mutex;
	bsp->WHT_Clr_BSP_Mutex = WHT_FSMC8080_BSP_Clr_Mutex;
    bsp->WHT_Write_Cmd     = WHT_FSMC8080_BSP_Write_Cmd;
    bsp->WHT_Write_Data    = WHT_FSMC8080_BSP_Write_Data;
    bsp->WHT_Write         = WHT_FSMC8080_BSP_Write;
    bsp->WHT_Read          = WHT_FSMC8080_BSP_Read;
}
